home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / Managed / Direct3D / FragmentLinker / FragmentLinker.cs next >
Encoding:
Text File  |  2004-09-27  |  27.4 KB  |  580 lines

  1. //-----------------------------------------------------------------------------
  2. // File: FragmentLinker.cs
  3. //
  4. // AboutMe please ...
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8.  
  9.  
  10. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  11. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  12.  
  13. using System;
  14. using Microsoft.DirectX;
  15. using Microsoft.DirectX.Direct3D;
  16. using Microsoft.Samples.DirectX;
  17. using Microsoft.Samples.DirectX.UtilityToolkit;
  18.  
  19. namespace FragmentLinkerSample
  20. {
  21.     /// <summary>FragmentLinker Sample Class</summary>
  22.     public class FragmentLinkerClass : IFrameworkCallback, IDeviceCreation
  23.     {
  24.         #region Creation
  25.         /// <summary>Create a new instance of the class</summary>
  26.         public FragmentLinkerClass(Framework f) 
  27.         { 
  28.             // Store framework
  29.             sampleFramework = f; 
  30.             // Create dialogs
  31.             hud = new Dialog(sampleFramework); 
  32.             sampleUI = new Dialog(sampleFramework); 
  33.         }
  34.         #endregion
  35.  
  36.         // Variables
  37.         private Framework sampleFramework = null; // Framework for samples
  38.         private Font statsFont = null; // Font for drawing text
  39.         private Sprite textSprite = null; // Sprite for batching text calls
  40.         private Effect effect = null; // D3DX Effect Interface
  41.         private ModelViewerCamera camera = new ModelViewerCamera();  // A model viewing camera
  42.         private bool isHelpShowing = true; // If true, renders the UI help text
  43.         private Dialog hud = null; // dialog for standard controls
  44.         private Dialog sampleUI = null; // dialog for sample specific controls
  45.  
  46.         // Sample specific variables
  47.         private FrameworkMesh mesh = null; // Mesh Object to be rendered
  48.         private Vector3 objectCenter; // Center of bounding sphere of object
  49.         private float objectRadius; // Radius of bounding sphere of object
  50.         private Matrix worldCenter; // World matrix to center the object
  51.         private ShaderFlags shaderFlags; // Shader compilation/linking flags
  52.         private FragmentLinker fragmentLinker = null; // Fragment linker interface
  53.         private GraphicsStream compiledFragments  = null;   // Buffer containing compiled fragments
  54.  
  55.         // HUD UI Control constants
  56.         private const int Static = -1;
  57.         private const int ToggleFullscreen =  1;
  58.         private const int ToggleReference =  3;
  59.         private const int ChangeDevice =  4;
  60.         private const int Animation =  5;
  61.         private const int Lighting =  6;
  62.  
  63.         /// <summary>
  64.         /// Called during device initialization, this code checks the device for some 
  65.         /// minimum set of capabilities, and rejects those that don't pass by returning false.
  66.         /// </summary>
  67.         public bool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool windowed)
  68.         {
  69.             // Skip back buffer formats that don't support alpha blending
  70.             if (!Manager.CheckDeviceFormat(caps.AdapterOrdinal, caps.DeviceType, adapterFormat, 
  71.                 Usage.QueryPostPixelShaderBlending, ResourceType.Textures, backBufferFormat))
  72.                 return false;
  73.  
  74.             return true;
  75.         }
  76.  
  77.         /// <summary>
  78.         /// This callback function is called immediately before a device is created to allow the 
  79.         /// application to modify the device settings. The supplied settings parameter 
  80.         /// contains the settings that the framework has selected for the new device, and the 
  81.         /// application can make any desired changes directly to this structure.  Note however that 
  82.         /// the sample framework will not correct invalid device settings so care must be taken 
  83.         /// to return valid device settings, otherwise creating the Device will fail.  
  84.         /// </summary>
  85.         public void ModifyDeviceSettings(DeviceSettings settings, Caps caps)
  86.         {
  87.             // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  88.             // then switch to SWVP.
  89.             if ( (!caps.DeviceCaps.SupportsHardwareTransformAndLight) ||
  90.                 (caps.VertexShaderVersion < new Version(1,1)) )
  91.             {
  92.                 settings.BehaviorFlags = CreateFlags.SoftwareVertexProcessing;
  93.             }
  94.             else
  95.             {
  96.                 settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing;
  97.             }
  98.  
  99.             // This application is designed to work on a pure device by not using 
  100.             // any get methods, so create a pure device if supported and using HWVP.
  101.             if ( (caps.DeviceCaps.SupportsPureDevice) && 
  102.                 ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0 ) )
  103.                 settings.BehaviorFlags |= CreateFlags.PureDevice;
  104.  
  105.             // Debugging vertex shaders requires either REF or software vertex processing 
  106.             // and debugging pixel shaders requires REF.  
  107. #if(DEBUG_VS)
  108.             if (settings.DeviceType != DeviceType.Reference )
  109.             {
  110.                 settings.BehaviorFlags &= ~CreateFlags.HardwareVertexProcessing;
  111.                 settings.BehaviorFlags |= CreateFlags.SoftwareVertexProcessing;
  112.             }
  113. #endif
  114. #if(DEBUG_PS)
  115.             settings.DeviceType = DeviceType.Reference;
  116. #endif
  117.  
  118.         }
  119.  
  120.         /// <summary>
  121.         /// This event will be fired immediately after the Direct3D device has been 
  122.         /// created, which will happen during application initialization and windowed/full screen 
  123.         /// toggles. This is the best location to create Pool.Managed resources since these 
  124.         /// resources need to be reloaded whenever the device is destroyed. Resources created  
  125.         /// here should be released in the Disposing event. 
  126.         /// </summary>
  127.         private void OnCreateDevice(object sender, DeviceEventArgs e)
  128.         {
  129.             // Initialize the stats font
  130.             statsFont = ResourceCache.GetGlobalInstance().CreateFont(e.Device, 15, 0, FontWeight.Bold, 1, false, CharacterSet.Default, Precision.Default, FontQuality.Default, PitchAndFamily.FamilyDoNotCare | PitchAndFamily.DefaultPitch, "Arial");
  131.  
  132.             // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  133.             // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  134.             // processing, and debugging pixel shaders requires REF.  The 
  135.             // ShaderFlags.Force * SoftwareNoOptimizations flag improves the debug experience in the 
  136.             // shader debugger.  It enables source level debugging, prevents instruction 
  137.             // reordering, prevents dead code elimination, and forces the compiler to compile 
  138.             // against the next higher available software target, which ensures that the 
  139.             // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  140.             // flags will cause slower rendering since the shaders will be unoptimized and 
  141.             // forced into software.  See the DirectX documentation for more information about 
  142.             // using the shader debugger.
  143.             shaderFlags = ShaderFlags.None;
  144. #if(DEBUG_VS)
  145.             shaderFlags |= ShaderFlags.ForceVertexShaderSoftwareNoOptimizations;
  146. #endif
  147. #if(DEBUG_PS)
  148.             shaderFlags |= ShaderFlags.ForcePixelShaderSoftwareNoOptimizations;
  149. #endif
  150.             // Read the D3DX effect file
  151.             // If this fails, there should be debug output as to 
  152.             // they the .fx file failed to compile
  153.             string path = Utility.FindMediaFile("FragmentLinker.fx");
  154.             effect = ResourceCache.GetGlobalInstance().CreateEffectFromFile(e.Device,
  155.                 path, null, null, shaderFlags, null);
  156.  
  157.             // Load the mesh
  158.             path = Utility.FindMediaFile("Dwarf\\dwarf.x");
  159.  
  160.             // Change the current directory to the mesh's directory so we can
  161.             // find the textures.
  162.             System.IO.FileInfo info = new System.IO.FileInfo(path);
  163.             System.IO.Directory.SetCurrentDirectory(info.Directory.FullName);
  164.  
  165.             mesh = new FrameworkMesh(e.Device, "dwarf.x");
  166.  
  167.             // Find the mesh's center, then generate a centering matrix.
  168.             using(VertexBuffer vb = mesh.SystemMesh.VertexBuffer)
  169.             {
  170.                 using (GraphicsStream stm = vb.Lock(0, 0, LockFlags.None))
  171.                 {
  172.                     try
  173.                     {
  174.                         objectRadius = Geometry.ComputeBoundingSphere(stm,
  175.                             mesh.SystemMesh.NumberVertices, mesh.SystemMesh.VertexFormat, out objectCenter);
  176.                         worldCenter = Matrix.Translation(-objectCenter);
  177.                     }
  178.                     finally
  179.                     {
  180.                         vb.Unlock();
  181.                     }
  182.                 }
  183.             }
  184.  
  185.             // Create the fragment linker interface
  186.             fragmentLinker = new FragmentLinker(e.Device, 0);
  187.  
  188.             // Compile the fragments to a buffer. The fragments must be linked together to form
  189.             // a shader before they can be used for rendering.
  190.             path = Utility.FindMediaFile("FragmentLinker.fx");
  191.             compiledFragments = Microsoft.DirectX.Direct3D.FragmentLinker.GatherFragmentsFromFile(path, null, null, shaderFlags);
  192.  
  193.             // Build the list of compiled fragments
  194.             fragmentLinker.AddFragments(compiledFragments);
  195.  
  196.             // Store the fragment handles
  197.             ComboBox cb1 = sampleUI.GetComboBox(Lighting);
  198.             cb1.Clear();
  199.             cb1.AddItem("Ambient", fragmentLinker.GetFragmentHandle("AmbientFragment"));
  200.             cb1.AddItem("Ambient & Diffuse", fragmentLinker.GetFragmentHandle("AmbientDiffuseFragment"));
  201.  
  202.             ComboBox cb2 = sampleUI.GetComboBox(Animation);
  203.             cb2.Clear();
  204.             cb2.AddItem("On" , fragmentLinker.GetFragmentHandle("ProjectionFragment_Animated"));
  205.             cb2.AddItem("Off", fragmentLinker.GetFragmentHandle("ProjectionFragment_Static"));
  206.  
  207.             // Link the desired fragments to create the vertex shader
  208.             LinkVertexShader();
  209.  
  210.             // Setup the camera's view parameters
  211.             camera.SetViewParameters(new Vector3(3.0f, 0.0f, -3.0f), Vector3.Empty);
  212.         }
  213.         
  214.         /// <summary>
  215.         /// Link together compiled fragments to create a vertex shader. The list of fragments
  216.         /// used is determined by the currently selected UI options.
  217.         /// </summary>
  218.         private void LinkVertexShader()
  219.         {
  220.             const int NumberFragments = 2;
  221.             EffectHandle[] aHandles = new EffectHandle[NumberFragments];
  222.             
  223.             aHandles[0] = sampleUI.GetComboBox(Animation).GetSelectedData() as EffectHandle;
  224.             aHandles[1] = sampleUI.GetComboBox(Lighting).GetSelectedData() as EffectHandle;
  225.  
  226.             // Link the fragments together to form a shader
  227.             string errors;
  228.             VertexShader vertexShader = fragmentLinker.LinkVertexShader("vs_1_1", shaderFlags, aHandles, out errors);
  229.  
  230.             // Associate this vertex shader with the effect object
  231.             effect.SetValue("MyVertexShader", vertexShader);
  232.         }
  233.  
  234.         /// <summary>
  235.         /// This event will be fired immediately after the Direct3D device has been 
  236.         /// reset, which will happen after a lost device scenario. This is the best location to 
  237.         /// create Pool.Default resources since these resources need to be reloaded whenever 
  238.         /// the device is lost. Resources created here should be released in the OnLostDevice 
  239.         /// event. 
  240.         /// </summary>
  241.         private void OnResetDevice(object sender, DeviceEventArgs e)
  242.         {
  243.             SurfaceDescription desc = e.BackBufferDescription;
  244.  
  245.             // Create a sprite to help batch calls when drawing many lines of text
  246.             textSprite = new Sprite(e.Device);
  247.  
  248.             // Setup the camera's projection parameters
  249.             float aspectRatio = (float)desc.Width / (float)desc.Height;
  250.             camera.SetProjectionParameters((float)Math.PI / 4, aspectRatio, 0.1f, 1000.0f);
  251.             camera.SetWindow(desc.Width, desc.Height);
  252.  
  253.             // Setup UI locations
  254.             hud.SetLocation(desc.Width-170, 0);
  255.             hud.SetSize(170,170);
  256.             sampleUI.SetLocation(desc.Width - 170, desc.Height - 350);
  257.             sampleUI.SetSize(170,300);
  258.         }
  259.  
  260.         /// <summary>
  261.         /// This event function will be called fired after the Direct3D device has 
  262.         /// entered a lost state and before Device.Reset() is called. Resources created
  263.         /// in the OnResetDevice callback should be released here, which generally includes all 
  264.         /// Pool.Default resources. See the "Lost Devices" section of the documentation for 
  265.         /// information about lost devices.
  266.         /// </summary>
  267.         private void OnLostDevice(object sender, EventArgs e)
  268.         {
  269.             if (textSprite != null)
  270.             {
  271.                 textSprite.Dispose();
  272.                 textSprite = null;
  273.             }
  274.         }
  275.  
  276.         /// <summary>
  277.         /// This callback function will be called immediately after the Direct3D device has 
  278.         /// been destroyed, which generally happens as a result of application termination or 
  279.         /// windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  280.         /// should be released here, which generally includes all Pool.Managed resources. 
  281.         /// </summary>
  282.         private void OnDestroyDevice(object sender, EventArgs e)
  283.         {
  284.             if(mesh != null)
  285.             {
  286.                 mesh.Dispose();
  287.                 mesh = null;
  288.             }
  289.         }
  290.  
  291.         /// <summary>
  292.         /// This callback function will be called once at the beginning of every frame. This is the
  293.         /// best location for your application to handle updates to the scene, but is not 
  294.         /// intended to contain actual rendering calls, which should instead be placed in the 
  295.         /// OnFrameRender callback.  
  296.         /// </summary>
  297.         public void OnFrameMove(Device device, double appTime, float elapsedTime)
  298.         {
  299.             Matrix worldMatrix;
  300.             Matrix worldViewProjectionMatrix;
  301.  
  302.             // Update the camera's position based on user input 
  303.             camera.FrameMove(elapsedTime);
  304.  
  305.             // Get the projection & view matrix from the camera class
  306.             worldMatrix = worldCenter * camera.WorldMatrix;
  307.             worldViewProjectionMatrix = worldMatrix * camera.ViewMatrix * camera.ProjectionMatrix;
  308.  
  309.             // Update the effect's variables.  Instead of using strings, it would 
  310.             // be more efficient to cache a handle to the parameter by calling 
  311.             // Effect.GetParameterByName
  312.             effect.SetValue("worldViewProjectionMatrix", worldViewProjectionMatrix);
  313.             effect.SetValue("worldMatrix", worldMatrix);
  314.             effect.SetValue("appTime", (float)appTime);
  315.         }
  316.  
  317.         /// <summary>
  318.         /// This callback function will be called at the end of every frame to perform all the 
  319.         /// rendering calls for the scene, and it will also be called if the window needs to be 
  320.         /// repainted. After this function has returned, the sample framework will call 
  321.         /// Device.Present to display the contents of the next buffer in the swap chain
  322.         /// </summary>
  323.         public void OnFrameRender(Device device, double appTime, float elapsedTime)
  324.         {
  325.             bool beginSceneCalled = false;
  326.  
  327.             // Clear the render target and the zbuffer 
  328.             device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, 0x002D32AA, 1.0f, 0);
  329.             try
  330.             {
  331.                 device.BeginScene();
  332.                 beginSceneCalled = true;
  333.  
  334.                 // Apply the technique contained in the effect
  335.                 int passes = effect.Begin(0);
  336.                 for(int pass = 0; pass < passes; pass++)
  337.                 {
  338.                     effect.BeginPass(pass);
  339.  
  340.                     // Render the mesh with the applied technique
  341.                     mesh.Render(device);
  342.  
  343.                     effect.EndPass();
  344.                 }
  345.                 effect.End();
  346.  
  347.                 // Show frame rate
  348.                 RenderText();
  349.  
  350.                 // Show UI
  351.                 hud.OnRender(elapsedTime);
  352.                 sampleUI.OnRender(elapsedTime);
  353.             }
  354.             finally
  355.             {
  356.                 if (beginSceneCalled)
  357.                     device.EndScene();
  358.             }
  359.         }
  360.  
  361.         /// <summary>
  362.         /// Render the help and statistics text. This function uses the Font object for 
  363.         /// efficient text rendering.
  364.         /// </summary>
  365.         private void RenderText()
  366.         {
  367.             // The helper object simply helps keep track of text position, and color
  368.             // and then it calls textFont.DrawText(textSprite, text, rect, DrawTextFormat.NoClip, color);
  369.             // If null is passed in as the sprite object, then it will work however the 
  370.             // textFont.DrawText() will not be batched together.  Batching calls improves performance.
  371.             TextHelper txtHelper = new TextHelper(statsFont, textSprite, 15);
  372.  
  373.             // Output statistics
  374.             txtHelper.Begin();
  375.             txtHelper.SetInsertionPoint(5,5);
  376.             txtHelper.SetForegroundColor(System.Drawing.Color.Yellow);
  377.             txtHelper.DrawTextLine(sampleFramework.FrameStats);
  378.             txtHelper.DrawTextLine(sampleFramework.DeviceStats);
  379.  
  380.             txtHelper.SetForegroundColor(System.Drawing.Color.White);
  381.             txtHelper.DrawTextLine("Selected fragments are linked on-the-fly to create the current shader" );
  382.  
  383.             // Draw help
  384.             if (isHelpShowing)
  385.             {
  386.                 txtHelper.SetInsertionPoint(10, sampleFramework.BackBufferSurfaceDescription.Height-15*6);
  387.                 txtHelper.SetForegroundColor(System.Drawing.Color.DarkOrange);
  388.                 txtHelper.DrawTextLine("Controls (F1 to hide):");
  389.  
  390.                 txtHelper.SetInsertionPoint(20, sampleFramework.BackBufferSurfaceDescription.Height-15*5);
  391.                 txtHelper.DrawTextLine( "Rotate model: Left mouse button\n" + 
  392.                                         "Rotate camera: Right mouse button\n" + 
  393.                                         "Zoom camera: Mouse wheel scroll\n" );
  394.  
  395.                 txtHelper.SetInsertionPoint(250, sampleFramework.BackBufferSurfaceDescription.Height-15*5);
  396.                 txtHelper.DrawTextLine( "Hide help: F1\n" + 
  397.                                         "Quit: ESC\n" );
  398.             }
  399.             else
  400.             {
  401.                 txtHelper.SetInsertionPoint(10, sampleFramework.BackBufferSurfaceDescription.Height-15*2);
  402.                 txtHelper.SetForegroundColor(System.Drawing.Color.White);
  403.                 txtHelper.DrawTextLine("Press F1 for help");
  404.             }
  405.  
  406.             txtHelper.End();
  407.         }
  408.  
  409.         /// <summary>
  410.         /// As a convenience, the sample framework inspects the incoming windows messages for
  411.         /// keystroke messages and decodes the message parameters to pass relevant keyboard
  412.         /// messages to the application.  The framework does not remove the underlying keystroke 
  413.         /// messages, which are still passed to the application's OnMsgProc callback.
  414.         /// </summary>
  415.         private void OnKeyEvent(System.Windows.Forms.Keys key, bool isKeyDown, bool isKeyUp)
  416.         {
  417.             if (isKeyDown)
  418.             {
  419.                 switch(key)
  420.                 {
  421.                     case System.Windows.Forms.Keys.F1:
  422.                         isHelpShowing = !isHelpShowing;
  423.                         break;
  424.                 }
  425.             }
  426.         }
  427.  
  428.         /// <summary>
  429.         /// Before handling window messages, the sample framework passes incoming windows 
  430.         /// messages to the application through this callback function. If the application sets 
  431.         /// noFurtherProcessing to true, the sample framework will not process the message
  432.         /// </summary>
  433.         public IntPtr OnMsgProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam, ref bool noFurtherProcessing)
  434.         {
  435.             // Give the dialog a chance to handle the message first
  436.             noFurtherProcessing = hud.MessageProc(hWnd, msg, wParam, lParam);
  437.             if (noFurtherProcessing)
  438.                 return IntPtr.Zero;
  439.  
  440.             noFurtherProcessing = sampleUI.MessageProc(hWnd, msg, wParam, lParam);
  441.             if (noFurtherProcessing)
  442.                 return IntPtr.Zero;
  443.  
  444.             // Pass all remaining windows messages to camera so it can respond to user input
  445.             camera.HandleMessages(hWnd, msg, wParam, lParam);
  446.  
  447.             return IntPtr.Zero;
  448.         }
  449.  
  450.         /// <summary>
  451.         /// Initializes the application
  452.         /// </summary>
  453.         public void InitializeApplication()
  454.         {
  455.             int y = 10;
  456.             
  457.             // Initialize the HUD
  458.             Button fullScreen = hud.AddButton(ToggleFullscreen,"Toggle full screen", 35, y, 125,22);
  459.             Button toggleRef = hud.AddButton(ToggleReference,"Toggle reference (F3)", 35, y += 24, 125,22);
  460.             Button changeDevice = hud.AddButton(ChangeDevice,"Change Device (F2)", 35, y += 24, 125,22);
  461.  
  462.             // Hook the button events for when these items are clicked
  463.             fullScreen.Click += new EventHandler(OnFullscreenClicked);
  464.             toggleRef.Click += new EventHandler(OnRefClicked);
  465.             changeDevice.Click += new EventHandler(OnChangeDeviceClicked);
  466.  
  467.             // Now add the sample specific UI
  468.             y = 10;
  469.             // Title font for comboboxes
  470.             sampleUI.SetFont(1, "Arial", 14, FontWeight.Bold );
  471.             Element element = sampleUI.GetDefaultElement(ControlType.StaticText, 0 );
  472.             element.FontIndex = 1;
  473.             element.textFormat = DrawTextFormat.Left | DrawTextFormat.Bottom;
  474.  
  475.             sampleUI.AddStatic(Static, "(V)ertex Animation", 20, 0, 105, 25 );
  476.             ComboBox cb1 = sampleUI.AddComboBox(Animation, 20, 25, 140, 24, System.Windows.Forms.Keys.V, false);
  477.             cb1.SetDropHeight(30);
  478.  
  479.             sampleUI.AddStatic(Static, "(L)ighting", 20, 50, 105, 25 );
  480.             ComboBox cb2 = sampleUI.AddComboBox(Lighting, 20, 75, 140, 24, System.Windows.Forms.Keys.L, false);
  481.             cb2.SetDropHeight(30);
  482.  
  483.             cb1.Changed += new EventHandler(OnVertexAnimationORLightingChanged);
  484.             cb2.Changed += new EventHandler(OnVertexAnimationORLightingChanged);
  485.         }
  486.  
  487.         /// <summary>Called when the change device button is clicked</summary>
  488.         private void OnChangeDeviceClicked(object sender, EventArgs e)
  489.         {
  490.             sampleFramework.ShowSettingsDialog(!sampleFramework.IsD3DSettingsDialogShowing);
  491.         }
  492.  
  493.         /// <summary>Called when the full screen button is clicked</summary>
  494.         private void OnFullscreenClicked(object sender, EventArgs e)
  495.         {
  496.             sampleFramework.ToggleFullscreen();
  497.         }
  498.  
  499.         /// <summary>Called when the ref button is clicked</summary>
  500.         private void OnRefClicked(object sender, EventArgs e)
  501.         {
  502.             sampleFramework.ToggleReference();
  503.         }
  504.  
  505.         /// <summary>
  506.         /// Entry point to the program. Initializes everything and goes into a message processing 
  507.         /// loop. Idle time is used to render the scene.
  508.         /// </summary>
  509.         static int Main() 
  510.         {
  511.             using(Framework sampleFramework = new Framework())
  512.             {
  513.                 FragmentLinkerClass sample = new FragmentLinkerClass(sampleFramework);
  514.                 // Set the callback functions. These functions allow the sample framework to notify
  515.                 // the application about device changes, user input, and windows messages.  The 
  516.                 // callbacks are optional so you need only set callbacks for events you're interested 
  517.                 // in. However, if you don't handle the device reset/lost callbacks then the sample 
  518.                 // framework won't be able to reset your device since the application must first 
  519.                 // release all device resources before resetting.  Likewise, if you don't handle the 
  520.                 // device created/destroyed callbacks then the sample framework won't be able to 
  521.                 // recreate your device resources.
  522.                 sampleFramework.Disposing += new EventHandler(sample.OnDestroyDevice);
  523.                 sampleFramework.DeviceLost += new EventHandler(sample.OnLostDevice);
  524.                 sampleFramework.DeviceCreated += new DeviceEventHandler(sample.OnCreateDevice);
  525.                 sampleFramework.DeviceReset += new DeviceEventHandler(sample.OnResetDevice);
  526.  
  527.                 sampleFramework.SetKeyboardCallback(new KeyboardCallback(sample.OnKeyEvent));
  528.                 sampleFramework.SetWndProcCallback(new WndProcCallback(sample.OnMsgProc));
  529.  
  530.                 sampleFramework.SetCallbackInterface(sample);
  531.                 try
  532.                 {
  533.                     // Show the cursor and clip it when in full screen
  534.                     sampleFramework.SetCursorSettings(true, true);
  535.  
  536.                     // Initialize
  537.                     sample.InitializeApplication();
  538.  
  539.                     // Initialize the sample framework and create the desired window and Direct3D 
  540.                     // device for the application. Calling each of these functions is optional, but they
  541.                     // allow you to set several options which control the behavior of the sampleFramework.
  542.                     sampleFramework.Initialize( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  543.                     sampleFramework.CreateWindow("FragmentLinker");
  544.                     sampleFramework.CreateDevice( 0, true, Framework.DefaultSizeWidth, Framework.DefaultSizeHeight, 
  545.                         sample);
  546.  
  547.                     // Pass control to the sample framework for handling the message pump and 
  548.                     // dispatching render calls. The sample framework will call your FrameMove 
  549.                     // and FrameRender callback when there is idle time between handling window messages.
  550.                     sampleFramework.MainLoop();
  551.  
  552.                 }
  553. #if(DEBUG)
  554.                 catch (Exception e)
  555.                 {
  556.                     // In debug mode show this error (maybe - depending on settings)
  557.                     sampleFramework.DisplayErrorMessage(e);
  558. #else
  559.             catch
  560.             {
  561.                 // In release mode fail silently
  562. #endif
  563.                     // Ignore any exceptions here, they would have been handled by other areas
  564.                     return (sampleFramework.ExitCode == 0) ? 1 : sampleFramework.ExitCode; // Return an error code here
  565.                 }
  566.  
  567.                 // Perform any application-level cleanup here. Direct3D device resources are released within the
  568.                 // appropriate callback functions and therefore don't require any cleanup code here.
  569.                 return sampleFramework.ExitCode;
  570.             }
  571.         }
  572.  
  573.         /// <summary>Fired when the vertex animation or lighting has changed</summary>
  574.         private void OnVertexAnimationORLightingChanged(object sender, EventArgs e)
  575.         {
  576.             LinkVertexShader();
  577.         }
  578.     }
  579. }
  580.